#pragma once

#include <ioavr.h>
#include <stdint.h>
#include "ring_buffer.h"

class Spi
{
  enum{SPI2X_shift = 2};
public:
  
  enum ClockDivider
  {
    Div2	= 1 << (SPI2X + SPI2X_shift) | 0 << SPR1 | 0 << SPR0,
    Div4	= 0 << (SPI2X + SPI2X_shift) | 0 << SPR1 | 0 << SPR0,
    Div8	= 1 << (SPI2X + SPI2X_shift) | 0 << SPR1 | 1 << SPR0,
    Div16	= 0 << (SPI2X + SPI2X_shift) | 0 << SPR1 | 1 << SPR0,
    Div32	= 1 << (SPI2X + SPI2X_shift) | 1 << SPR1 | 0 << SPR0,
    Div64	= 0 << (SPI2X + SPI2X_shift) | 1 << SPR1 | 0 << SPR0,
    Div128	= 0 << (SPI2X + SPI2X_shift) | 1 << SPR1 | 1 << SPR0
  };
  
  enum SpiMode
  {
    Mode0	= (0<<CPOL)|(0<<CPHA),
    Mode1	= (1<<CPOL)|(0<<CPHA),
    Mode2	= (0<<CPOL)|(1<<CPHA),
    Mode3	= (1<<CPOL)|(1<<CPHA)
  };
  
  enum{ClockDividerMask = 1 << SPR1 | 1 << SPR0};
  
  template <ClockDivider DIVIDER, SpiMode MODE>
    static void Init()
    {
      if(DIVIDER & (1 << (SPI2X + SPI2X_shift)))
        SPSR |= 1 << SPI2X;
      else 
        SPSR &= ~(1 << SPI2X);
      
      SPCR = (1<<SPE)| (1<<MSTR) | MODE| (DIVIDER & ClockDividerMask);
    }
 
  static uint8_t ReadWrite(uint8_t outValue)
  {
    SPDR = outValue;
    while(!(SPSR & (1<<SPIF)));    
    return SPDR;
  }
};
